package com.alkalinesolutions.json.core.impl;

import java.io.Serializable;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.alkalinesolutions.json.core.DuplicateKeyException;
import com.alkalinesolutions.json.core.JSONException;
import com.alkalinesolutions.json.core.Messages;

public class StructureEmitter {
	public Object parse(Iterable<JSONEvent> events) throws JSONException {
		try {
			Iterator<JSONEvent> it = events.iterator();
			while (it.hasNext()) {
				JSONEvent event = it.next();
				switch (event.getType()) {
					case StartArray:
						List<Serializable> result = new ArrayList<Serializable>();
						parse(result, it);
						return result;
					case StartObject:
						Map<String, Serializable> resultmap = new LinkedHashMap<String, Serializable>();
						parse(resultmap, it);
						return resultmap;
					default:
						throw new JSONException();
				}
			}
		throw new JSONException(Messages.getString("StructureEmitter.0")); //$NON-NLS-1$
		}
		catch (UndeclaredThrowableException e) {
			if (e.getCause() instanceof JSONException) {
				throw  (JSONException)e.getCause();
			}
			throw new JSONException(e.getCause());
		}

	}
	private void parse(Map<String, Serializable> parent, Iterator<JSONEvent> it)throws JSONException {
		while (it.hasNext()) {
			JSONEvent event = it.next();
			Serializable data = event.getData();
			String key = event.getKey();
			
			if (parent.containsKey(key))
				throw new DuplicateKeyException(key);
			
			switch (event.getType()) {
			case Boolean:
			case Null:
			case Number:
			case String:
				parent.put(key, data);
				break;
			case StartArray:
				ArrayList<Serializable> array = new ArrayList<Serializable>();
				parse(array, it);
				parent.put(key, array);
				break;
			case StartObject:
				LinkedHashMap<String, Serializable> object = new LinkedHashMap<String, Serializable>();
				parse(object, it);
				parent.put(key, object);
				break;
			case EndArray:
			case EndObject:
				return;
			}
		}
		throw new JSONException(Messages.getString("StructureEmitter.0")); //$NON-NLS-1$
	}
		
	private void parse(List<Serializable> parent, Iterator<JSONEvent> it)throws JSONException {
		while (it.hasNext()) {
			JSONEvent event = it.next();
			Serializable data = event.getData();
			switch (event.getType()) {
			case Boolean:
			case Null:
			case Number:
			case String:
				parent.add(data);
				break;
			case StartArray:
				ArrayList<Serializable> array = new ArrayList<Serializable>();
				parse(array, it);
				parent.add(array);
				break;
			case StartObject:
				LinkedHashMap<String, Serializable> object = new LinkedHashMap<String, Serializable>();
				parse(object, it);
				parent.add(object);
				break;
			case EndArray:
			case EndObject:
				return;
			}
		}
		throw new JSONException(Messages.getString("StructureEmitter.0")); //$NON-NLS-1$
	}
}